package com.ych.modules.api.unAuthorInfc.login.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.ych.SDK.alibaba.ossSDK.AliOssUtil;
import com.ych.SDK.alibaba.smsSDK.SmsUtil;
import com.ych.modules.api.unAuthorInfc.login.entity.LoginVo;
import com.ych.modules.api.unAuthorInfc.login.entity.ModifyVo;
import com.ych.modules.api.unAuthorInfc.login.entity.RegisterVo;
import com.ych.modules.api.unAuthorInfc.login.service.IApiUserInfoService;
import com.ych.modules.base.dbEntity.TUserInfoEntity;
import com.ych.modules.base.dbEntity.TUserTokenEntity;
import com.ych.modules.base.service.ITUserInfoService;
import com.ych.modules.base.service.ITUserTokenService;
import com.ych.redis.RedisLockUtil;
import com.ych.redis.RedisUtil;
import com.ych.redis.config.RedisKeyConfig;
import com.ych.utils.TLMap;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 * Author: Usopp.tsui
 * Date: 2020/12/10
 * Time: 14:03
 * Description:
 */
@Service("IApiUserInfoService")
public class ApiUserInfoServiceImpl implements IApiUserInfoService {
    @Autowired
    private ITUserInfoService itUserInfoService;

    @Autowired
    private ITUserTokenService itUserTokenService;

    @Autowired
    private RedisUtil  redisUtil;
    @Autowired
    private AliOssUtil aliOssUtil;

    @Override
    public Map<String, Object> login(LoginVo loginVo) {
        TUserInfoEntity userInfoEntity = this.queryByMobile(loginVo.getMobile());
        if (null == userInfoEntity) {
            throw new RuntimeException("用户名或密码不正确[N]");
        }
        if (!userInfoEntity.getPassword().equals(new Sha256Hash(loginVo.getPassword(), userInfoEntity.getSalt()).toHex())) {//新系统匹配方式
            throw new RuntimeException("用户名或密码不正确[P]");
        }
        //生成数据库token票据
        TUserTokenEntity tokenEntity = itUserTokenService.createToken(userInfoEntity.getUserId());
        if (null == tokenEntity) {
            throw new RuntimeException("无法验证用户身份");
        }
        //不将用户密码返回去
        userInfoEntity.setPassword(null);
        userInfoEntity.setSalt(null);
        TLMap.setUserId(userInfoEntity.getUserId());//将user装入当前线程内
        TLMap.setToken(tokenEntity.getToken());//将token装入当前线程内
        TLMap.setMobile(userInfoEntity.getMobile());
        Subject subject = SecurityUtils.getSubject();
        //将token交给shiro认证
        subject.login(new UsernamePasswordToken(tokenEntity.getToken(), tokenEntity.getToken()));
        Map<String, Object> map = new HashMap<>();
        map.put("token", tokenEntity.getToken());
        map.put("expire", RedisKeyConfig.expireTime);
        map.put("user", userInfoEntity);
        //异步处理抽奖券分发
        if ("1".equals(userInfoEntity.getIsTicket())) {
            //上锁，避免重复分发抽奖券
            String key = RedisKeyConfig.rewardRaffleTicket + userInfoEntity.getUserId();
            try {
                if (RedisLockUtil.tryLock(key, userInfoEntity.getUserId(), RedisKeyConfig.leaseTime)) {
                    this.dealRaffleTicket(userInfoEntity);
                }
            } catch (Exception e) {
            } finally {
                //解锁
                RedisLockUtil.unlock(key, userInfoEntity.getUserId());
            }
        }
        return map;
    }

    /**
     * 异步处理抽奖券分发
     *
     * @param userInfoEntity
     */
    private void dealRaffleTicket(TUserInfoEntity userInfoEntity) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
        try {
            fixedThreadPool.execute(() -> {
                try {
//                    Thread.sleep(1000);
                    //开启异步线程进行分发抽奖券
                    itUserInfoService.rewardRaffleTicket(userInfoEntity.getUserId());
                } catch (Exception e3) {
                }
            });
        } catch (Exception e1) {
        } finally {
            fixedThreadPool.shutdown();
        }
    }

    @Override
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public TUserInfoEntity register(RegisterVo registerVo) {
        String redisKey = RedisKeyConfig.msgCode + registerVo.getMobile();
        Object o = redisUtil.redisTemplate().opsForValue().get(redisKey);
        if (null == o) {
            throw new RuntimeException("注册验证码过期,请重新获取");
        }
        int regCode = (Integer) o;
        int smscode = Integer.valueOf(registerVo.getCode());
        if (smscode != regCode) {
            throw new RuntimeException("验证码错误");
        }
        if (StringUtils.isBlank(registerVo.getMobile())) {
            throw new RuntimeException("手机号不可为空");
        }
        if (StringUtils.isBlank(registerVo.getPassword())) {
            throw new RuntimeException("密码不可为空");
        }
        if (StringUtils.isBlank(registerVo.getRecommenderInvitation())) {
//            throw new RuntimeException("邀请码不可为空");
            registerVo.setRecommenderInvitation("1");//邀请码为空，设置一个默认邀请码
        }
        //查询用户信息
        TUserInfoEntity modeTUserInfoEntity = this.queryByMobile(registerVo.getMobile());
        if (null != modeTUserInfoEntity) {
            throw new RuntimeException("用户存在,请勿重复注册");
        }
        TUserInfoEntity user = new TUserInfoEntity();
        user.setMobile(registerVo.getMobile());//用户手机号
        user.setPassword(registerVo.getPassword());//用户密码
        user.setUserHeadUrl("default/default_user_head.png");//用户默认头像
        user.setStatus("0");
        List<String> list = new ArrayList<>();
        list.add("2");//默认为注册用户
        user.setRoleIdList(list);
        user.setRecommenderInvitation(registerVo.getRecommenderInvitation());
        this.saveUser(user);//保存用户
        //保存完毕后,帮当前用户进行注册
        TUserInfoEntity tUserInfoEntity = this.queryByMobile(registerVo.getMobile());
        if (null == tUserInfoEntity) {
            throw new RuntimeException("服务器繁忙,注册失败");
        }
        TUserTokenEntity tokenEntity = itUserTokenService.createToken(tUserInfoEntity.getUserId());
        if (null == tokenEntity) {
            throw new RuntimeException("校验注册用户身份失败");
        }
        TLMap.setUserId(user.getUserId());
        TLMap.setToken(tokenEntity.getToken());
        TLMap.setMobile(user.getMobile());
        Subject subject = SecurityUtils.getSubject();
        //将token交给shiro认证
        subject.login(new UsernamePasswordToken(tokenEntity.getToken(), tokenEntity.getToken()));
        //删除验证码
        redisUtil.redisTemplate().delete(redisKey);
        //设置一下密码，用于登录时候使用
        tUserInfoEntity.setPassword(registerVo.getPassword());
        return tUserInfoEntity;
    }

    @Override
    public void getSmsCaptcha(String mobile) {
        String redisKey = RedisKeyConfig.msgCode + mobile;
        if (null != redisUtil.redisTemplate().opsForValue().get(redisKey)) {
            throw new RuntimeException("验证码已发到您的手机，如未收到请稍后重新发送!");
        }
        TUserInfoEntity userInfoEntity = this.queryByMobile(mobile);
        if (null != userInfoEntity) {
            throw new RuntimeException("该手机号已注册！");
        }
        //生成4位短信验证码
        Integer code = (int) ((Math.random() * 9 + 1) * 100000);
        boolean status = SmsUtil.sendSms(mobile, code);
        if (!status) {
            throw new RuntimeException("发送失败");
        }
        //发送成功
        redisUtil.redisTemplate().opsForValue().set(redisKey, code);
        redisUtil.redisTemplate().expire(redisKey, 60 * 5L, TimeUnit.SECONDS);
    }

    @Override
    public void modifyPassword(ModifyVo modifyVo) {
//        String redisKey = RedisKeyConfig.msgCode + modifyVo.getMobile();
//        Object o = redisUtil.redisTemplate().opsForValue().get(redisKey);
//        if (null == o) {
//            throw new RuntimeException("注册验证码过期,请重新获取");
//        }
//        int regCode = (Integer) o;
//        int smscode = Integer.valueOf(modifyVo.getCode());
//        if (smscode != regCode) {
//            throw new RuntimeException("验证码错误");
//        }
        if (StringUtils.isBlank(modifyVo.getMobile())) {
            throw new RuntimeException("手机号不可为空");
        }
        //查询用户信息
        TUserInfoEntity modeTUserInfoEntity = this.queryByMobile(modifyVo.getMobile());
        if (null == modeTUserInfoEntity) {
            throw new RuntimeException("用户不存在！请先注册！");
        }
        //比较原密码
//        if (!modeTUserInfoEntity.getPassword().equals(new Sha256Hash(modifyVo.getOldPwd(), modeTUserInfoEntity.getSalt()).toHex())) {//新系统匹配方式
//            throw new RuntimeException("原密码错误！");
//        }
        //新密码加密
        String newPwd = new Sha256Hash(modifyVo.getNewPwd(), modeTUserInfoEntity.getSalt()).toHex();
        TUserInfoEntity tempUserInfoEntity = new TUserInfoEntity();
        tempUserInfoEntity.setUserId(modeTUserInfoEntity.getUserId());
        tempUserInfoEntity.setPassword(newPwd);
        itUserInfoService.updateById(tempUserInfoEntity);
    }

    /**
     * 保存用户
     *
     * @param user
     */
    private void saveUser(TUserInfoEntity user) {
        itUserInfoService.save(user);
    }

    /**
     * 通过手机号查询
     *
     * @param mobile
     * @return
     */
    private TUserInfoEntity queryByMobile(String mobile) {
        Wrapper<TUserInfoEntity> wrapper = new EntityWrapper<TUserInfoEntity>()
                .where("1=1")
                .eq("mobile", mobile);
        TUserInfoEntity userInfoEntity = itUserInfoService.selectOne(wrapper);
        if (null == userInfoEntity) {
            return null;
        }
        userInfoEntity.setUserHeadUrl(aliOssUtil.getOssObjectDownAuthUrl(userInfoEntity.getUserHeadUrl()));
        //查询推荐人信息
        TUserInfoEntity inviterEntity = itUserInfoService.selectById(userInfoEntity.getRecommenderUserId());
        TUserInfoEntity tempEntity = new TUserInfoEntity();
        tempEntity.setMobile(inviterEntity.getMobile());
        tempEntity.setUserName(inviterEntity.getUserName());
        tempEntity.setUserHeadUrl(aliOssUtil.getOssObjectDownAuthUrl(inviterEntity.getUserHeadUrl()));
        userInfoEntity.setInviterEntity(tempEntity);
        return userInfoEntity;
    }
}
